<?php

namespace seecms\db\traits;

use seecms\db\SeeDb;
use seecms\db\SeeDbException;
use seecms\See;

trait SeeDbSelectMethod
{
    /**
     * 查找单条记录
     * 如果没有任何的查询条件 并且也没有调用order方法的话 ，find查询不会返回任何结果
     * @return array|\PDOStatement|string|null
     */
    public function find($id = null)
    {
        if ($id) {
            unset($this->options['where']);
            $this->where('id', $id);
        } elseif (empty($this->options['where']) && empty($this->options['order'])) {
            return null;
        }

        $result = $this->limit(1)->select();

        if ($result instanceof \PDOStatement || is_string($result)) {
            return $result;
        }

        return $result[0] ?? null;
    }

    /**
     * 查询满足条件的所有数据
     * @return mixed 查询结果集
     * @throws SeeDbException
     */
    public function select()
    {

        $options = $this->parseExpress();

        // 生成sql
        $sql = $this->builder->select($options);

        // 获取绑定值
        $bind = $this->getBind();

        // 判断调试模式,返回sql
        if (isset($options['debug']) && $options['debug']) {
            return $this->connection->getRealSql($sql, $bind);
        }

        $obj = (isset($options['obj']) && $options['obj']);

        $result = $this->query($sql, $bind, $obj);

        // 触发查询事件
        SeeDb::trigger('select', $this->connection, $options);

        return $result;
    }

    /**
     * 分页查询
     * @param $page_id
     * @param $page_size
     * @return array
     * @throws SeeDbException
     */
    public function paginate($page_id = null, $page_size = null): array
    {

        if (is_null($page_id)) {
            $page_id = See::request()->param('page_id');
        }

        if (is_null($page_size)) {
            $page_size = See::request()->param('page_size');
        }

        $page_id = intval($page_id);
        $page_size = intval($page_size);
        if ($page_size <= 0) {
            $page_size = 15;
        } elseif ($page_size > 200) {
            $page_size = 200;
        }

        // 获取总数
        $option = $this->options;
        $total = $this->count();

        $this->options = $option;
        $data = $this->page($page_id, $page_size)->select();

        $last_page = (int)ceil($total / $page_size);

        return [
            'total' => $total,
            'current_page' => $page_id,
            'last_page' => $last_page,
            'pre_page' => $page_size,
            'has_more' => $page_id < $last_page,
            'data' => $data
        ];
    }

    /**
     * 查询列
     * @param $column
     * @param string $key
     * @return array|mixed
     * @throws SeeDbException
     */
    public function column($column, string $key = '')
    {
        if (empty($key) || trim($key) === '') {
            $key = null;
        }

        if (is_string($column)) {
            $column = trim($column);
            if ('*' !== $column) {
                $column = array_map('trim', explode(',', $column));
            }
        } elseif (is_array($column)) {
            if (in_array('*', $column)) {
                $column = '*';
            }
        } else {
            throw new SeeDbException('not support column type');
        }

        $field = $column;
        if ('*' !== $column && $key && !in_array($key, $column)) {
            $field[] = $key;
        }

        $this->setOption('field', $field);

        $result = $this->select();

        if (empty($result)) {
            $result = [];
        } elseif ('*' !== $column && count($column) === 1) {
            $column = array_shift($column);
            if (strpos($column, ' ')) {
                $column = substr(strrchr(trim($column), ' '), 1);
            }

            $result = array_column($result, $column, $key);
        } elseif ($key) {
            $result = array_column($result, null, $key);
        }

        return $result;
    }

    public function chunk(int $count, callable $callback, $column = null, string $order = 'asc'): bool
    {
        $options = $this->getOptions();
        $column = $column ?: $this->getPk();

        if (isset($options['order'])) {
            unset($options['order']);
        }

        $bind = $this->bind;

        if (is_array($column)) {
            $times = 1;
            $query = $this->options($options)->page($times, $count);
        } else {
            $query = $this->options($options)->limit($count);
            $key = $column;
        }

        $result = $query->order($column, $order)->select();

        while (count($result) > 0) {
            if (false === call_user_func($callback, $result)) {
                return false;
            }

            if (isset($times)) {
                $times++;
                $query = $this->options($options)->page($times, $count);
            } else {
                $end = array_pop($result);
                $lastId = is_array($end) ? $end[$key] : $end->getData($key);

                $query = $this->options($options)
                    ->limit($count)
                    ->where($column, 'asc' == strtolower($order) ? '>' : '<', $lastId);
            }

            $result = $query->bind($bind)->order($column, $order)->select();
        }

        return true;
    }
}